﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using System.Timers;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Windows.Forms;

namespace FaceCompare
{
    public enum ImageStatus { OK, ERROR }
    public class ImageProcessor
    {
        protected string m_imageId;

        protected string m_file;
        protected picture m_picture;
        protected static int m_count = 0;
        protected FaceCompareEntities m_db = new FaceCompareEntities();
        protected int m_maxCount;
        protected System.Timers.Timer m_uploadTimer;
        protected static UTF8Encoding Encoding = new UTF8Encoding();
        public ManualResetEvent FinishedEvent;
        public ImageStatus Status;



        public ImageProcessor(picture picture, int maxCount)
        {
            m_picture = picture;
            m_file = picture.fileName;
            m_maxCount = maxCount;
            m_uploadTimer = new System.Timers.Timer(2000);
            m_uploadTimer.AutoReset = false;
        }

        public void Upload()
        {
            if (m_picture.status == 0)
            {
                try
                {

                    var data = File.ReadAllBytes(m_file);
                    var request = (HttpWebRequest)WebRequest.Create("http://www.betafaceapi.com/service.svc/UploadNewImage_File");
                    request.Timeout = 1000000000;
                    request.Method = "POST";
                    request.ContentType = "application/xml";
                    var requestBody = new StringBuilder();
                    requestBody.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
                    requestBody.Append("<ImageRequestBinary>");
                    requestBody.Append("<api_key>d45fd466-51e2-4701-8da8-04351c872236</api_key>");
                    requestBody.Append("<api_secret>171e8465-f548-401d-b63b-caf0dc28df5f</api_secret>");
                    requestBody.Append("<detection_flags></detection_flags>");
                    requestBody.Append("<imagefile_data>");
                    requestBody.Append(Convert.ToBase64String(data));
                    requestBody.Append("</imagefile_data>");
                    requestBody.Append("<original_filename>");
                    requestBody.Append(m_file);
                    requestBody.Append("</original_filename>");
                    requestBody.Append("</ImageRequestBinary>");
                    request.ContentLength = requestBody.Length;
                    using (Stream stream = request.GetRequestStream())
                    {
                        var requestBytes = Encoding.GetBytes(requestBody.ToString());
                        stream.Write(requestBytes, 0, requestBytes.Length);
                    }
                    request.Timeout = 1000000000;
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    var doc = new XPathDocument(response.GetResponseStream());
                    XPathNavigator nav = doc.CreateNavigator();
                    var expr = nav.Compile("/BetafaceImageResponse/string_response");
                    var iterator = nav.Select(expr);
                    if (iterator.MoveNext())
                    {
                        if (iterator.Current.Value != "ok")
                        {
                            Finish(ImageStatus.ERROR);
                            return;
                        }
                        else
                        {
                            expr = nav.Compile("/BetafaceImageResponse/img_uid");
                            iterator = nav.Select(expr);
                            if (iterator.MoveNext())
                            {
                                m_imageId = iterator.Current.Value;
                                LogStatusToDB(m_imageId, m_file);
                            }
                            m_uploadTimer.Elapsed += new ElapsedEventHandler(m_uploadTimer_Elapsed);
                            m_uploadTimer.Start();
                        }
                    }
                }
                catch (Exception ex)
                {
                  //  MessageBox.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
                }
            }
            else
            {

                m_imageId = m_picture.betaImageId;
                m_uploadTimer.Elapsed += new ElapsedEventHandler(m_uploadTimer_Elapsed);
                m_uploadTimer.Start();
            }
        }

        private void LogStatusToDB(string image_id, string m_file)
        {
            var picture = m_db.picture.First(p => p.fileName == m_file);
            picture.betaImageId = image_id;
            picture.status = 1;
            m_db.SaveChanges();
        }

        private void Finish(ImageStatus imageStatus)
        {
            Status = imageStatus;
            Interlocked.Increment(ref m_count);
            if (m_count >= m_maxCount)
            {
                FinishedEvent.Set();
            }
        }

        void m_uploadTimer_Elapsed(object sender, ElapsedEventArgs e)
        {

            try
            {
                m_uploadTimer.Stop();
                var request = (HttpWebRequest)WebRequest.Create("http://www.betafaceapi.com/service.svc/GetImageInfo");
                request.Timeout = 1000000000;
                request.Method = "POST";
                request.ContentType = "application/xml";
                var requestBody = new StringBuilder();
                requestBody.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
                requestBody.Append("<ImageInfoRequestUid xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
                requestBody.Append("<api_key>d45fd466-51e2-4701-8da8-04351c872236</api_key>");
                requestBody.Append("<api_secret>171e8465-f548-401d-b63b-caf0dc28df5f</api_secret>");
                requestBody.Append("<img_uid>" + m_imageId + "</img_uid>");
                requestBody.Append("</ImageInfoRequestUid>");

                request.ContentLength = requestBody.Length;
                using (Stream stream = request.GetRequestStream())
                {
                    var requestBytes = Encoding.GetBytes(requestBody.ToString());
                    stream.Write(requestBytes, 0, requestBytes.Length);
                }
                request.Timeout = 1000000000;
                var response = (HttpWebResponse)request.GetResponse();
                var doc = new XPathDocument(response.GetResponseStream());
                var nav = doc.CreateNavigator();
                var expr = nav.Compile("/BetafaceImageInfoResponse/int_response");
                var iterator = nav.Select(expr);
                if (iterator.MoveNext())
                {
                    if (iterator.Current.Value == "0")
                    {
                        var picture = m_db.picture.First(p => p.fileName == m_file);
                        picture.status = 2;
                        m_db.SaveChanges();
                        ProcessFaces(nav);
                        return;
                    }

                }
                m_uploadTimer.Start();
            }
            catch (Exception ex)
            {
               // MessageBox.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
            }

        }


        private void ProcessFaces(XPathNavigator nav)
        {
            try
            {

                var expr = nav.Compile("/BetafaceImageInfoResponse/faces/FaceInfo");
                var iterator = nav.Select(expr);
                var finishedEvent = new ManualResetEvent(false);
                if (iterator.Count == 0)
                {
                    var pp = m_db.picture.First(p => p.fileName == m_picture.fileName);
                    pp.status = 999;
                    m_db.SaveChanges();
                    Finish(ImageStatus.OK);
                    return;
                }
                long currentCount = 0;
                Ref<long> currentCountRef = new Ref<long>(
                    () => { return Interlocked.Read(ref currentCount); },
                    v => { Interlocked.Exchange(ref currentCount, v); },
                    () => { return Interlocked.Increment(ref currentCount); });
                var faceCount = 0;
                var count = iterator.Count;
                if (count > 3)
                {
                    var pic = m_db.picture.First(p => p.fileName == m_picture.fileName);
                    pic.status = 30;
                    m_db.SaveChanges();
                    Finish(ImageStatus.OK);
                    return;

                }
                while (iterator.MoveNext())
                {
                    try
                    {
                        var face = new face();
                        nav = iterator.Current;
                        expr = nav.Compile("uid");
                        var iterator1 = nav.Select(expr);
                        if (iterator1.MoveNext())
                        {
                            face.face_id = iterator1.Current.Value;
                        }
                        var fa = m_db.face.FirstOrDefault(p => p.face_id == face.face_id);
                        if (fa == null)
                        {
                            face.betaImageId = m_imageId;
                            var image = m_db.picture.FirstOrDefault(p => p.betaImageId == m_imageId);
                            if (image != null)
                            {
                                face.fileName = image.fileName;
                                face.pid = image.pid;
                            }
                            expr = nav.Compile("tags/TagInfo");
                            iterator1 = nav.Select(expr);
                            while (iterator1.MoveNext())
                            {
                                nav = iterator1.Current;
                                var value = "";
                                expr = nav.Compile("name");
                                var iterator2 = nav.Select(expr);
                                if (iterator2.MoveNext())
                                {
                                    switch (iterator2.Current.Value)
                                    {
                                       
                                        case "beard":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.beard = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.beardC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.beardC = 999;
                                            }
                                            break;
                                        case "gender":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.gender = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.genderC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.genderC = 999;
                                            }
                                            break;
                                        case "glasses":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.glasses = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.glassesC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.glassesC = 999;
                                            }
                                            break;
                                        case "mustache":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.mustache = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.mustacheC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.mustacheC = 999;
                                            }
                                            break;
                                        case "smile":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.smile = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.smileC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.smileC = 999;
                                            }
                                            break;
                                        case "race":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.race = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.raceC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.raceC = 999;
                                            }
                                            break;
                                        case "age":
                                            expr = nav.Compile("value");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                face.age = iterator2.Current.Value;
                                            }
                                            expr = nav.Compile("confidence");
                                            iterator2 = nav.Select(expr);
                                            if (iterator2.MoveNext())
                                            {
                                                value = iterator2.Current.Value;
                                                face.ageC = float.Parse(value);
                                            }
                                            else
                                            {
                                                face.ageC = 999;
                                            }
                                            break;
                                    }

                                }
                            }
                            face.status = 0;
                            faceCount++;
                            face.num_figures = faceCount;
                            m_db.AddToface(face);
                            m_db.SaveChanges();
                        }
                        else
                        {

                            face = fa;
                            if (face.status == 1)
                            {
                                count--;
                                continue;
                            }
                        }

                      

                    }
                    catch (Exception ex)
                    {
                     //   MessageBox.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
                    }
                }
          
                Finish(ImageStatus.OK);
            }
            catch (Exception ex)
            {
              //  MessageBox.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
            }
        }

    }
}
